package com.fly.refresh.back;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import com.fly.refresh.entity.Person;
import com.fly.refresh.entity.Result;
import com.fly.refresh.entity.Welcome;

import lombok.extern.slf4j.Slf4j;

/**
 * 监听文件变化（推荐）
 */
@Slf4j
@Component
public class ReloadByFileAlterationMonitor
{
    @Autowired
    private Person person;
    
    @Autowired
    private Welcome welcome;
    
    /**
     * thread-safe
     */
    YAMLMapper yamlMapper = new YAMLMapper();
    
    /**
     * thread-safe
     */
    JavaPropsMapper javaPropsMapper = new JavaPropsMapper();
    
    /**
     * 初始化yml文件监听器
     */
    @PostConstruct
    public void initYamlMonitor()
    {
        try
        {
            URL url = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX);
            if (ResourceUtils.isFileURL(url))
            {
                FileAlterationObserver observer = new FileAlterationObserver(url.getPath(), FileFilterUtils.suffixFileFilter(".yml"));
                observer.addListener(new FileAlterationListenerAdaptor()
                {
                    @Override
                    public void onFileChange(File file)
                    {
                        log.info("★★★★★★★★ {} changed.", file.getName());
                        if (StringUtils.equals("application-dev.yml", file.getName()))
                        {
                            try
                            {
                                // yaml to JavaBean
                                String text = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
                                Result result = yamlMapper.readValue(text, Result.class);
                                
                                // Welcome属性拷贝
                                if (result != null && result.getWelcome() != null)
                                {
                                    BeanUtils.copyProperties(result.getWelcome(), welcome);
                                    log.info("#### autoRefresh to: {}", welcome);
                                }
                                // Person属性拷贝
                                if (result != null && result.getPerson() != null)
                                {
                                    BeanUtils.copyProperties(result.getPerson(), person);
                                    log.info("#### autoRefresh to: {}", person);
                                }
                            }
                            catch (IOException e)
                            {
                                log.error(e.getMessage(), e.getCause());
                            }
                        }
                    }
                });
                long interval = TimeUnit.SECONDS.toMillis(10);
                FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
                monitor.start();
            }
        }
        catch (Exception e)
        {
            log.error(e.getMessage(), e.getCause());
        }
    }
    
    /**
     * 初始化Properties文件监听器
     */
    @PostConstruct
    public void initPropsMonitor()
    {
        try
        {
            URL url = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX);
            if (ResourceUtils.isFileURL(url))
            {
                FileAlterationObserver observer = new FileAlterationObserver(url.getPath(), FileFilterUtils.suffixFileFilter(".properties"));
                observer.addListener(new FileAlterationListenerAdaptor()
                {
                    @Override
                    public void onFileChange(File file)
                    {
                        log.info("★★★★★★★★ {} changed.", file.getName());
                        if (StringUtils.equals("welcome.properties", file.getName()))
                        {
                            try
                            {
                                // Properties to JavaBean
                                Properties props = PropertiesLoaderUtils.loadProperties(new ClassPathResource(file.getName()));
                                Result result = javaPropsMapper.readPropertiesAs(props, Result.class);
                                if (result != null && result.getWelcome() != null)
                                {
                                    String value = result.getWelcome().getMessage();
                                    log.info("#### autoRefresh to: {}", value);
                                    welcome.setMessage(value);
                                }
                            }
                            catch (IOException e)
                            {
                                log.error(e.getMessage(), e.getCause());
                            }
                        }
                    }
                });
                long interval = TimeUnit.SECONDS.toMillis(10);
                FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
                monitor.start();
            }
        }
        catch (Exception e)
        {
            log.error(e.getMessage(), e.getCause());
        }
    }
}
